package teamUFPE;



import java.awt.Color;
import java.io.IOException;

import myTeam.Apelacao;
import myTeam.Predicao;
import robocode.HitByBulletEvent;
import robocode.HitWallEvent;
import robocode.MessageEvent;
import robocode.Rules;
import robocode.ScannedRobotEvent;
import robocode.TeamRobot;
import myTeam.RobotColors;

public class MataTudo extends TeamRobot{

	ScannedRobotEvent lastEvent;

	private String nameEnemy;
	private double posXEnemy;
	private double posYEnemy;

	private double helpPosXEnemy;
	private double helpPosYEnemy;

	private double giroEnemy;
	private int lastTimeEnemy;

	private int direcao = 1;
	private double headingEnemy;
	private double enemySpeed;
	private long turnRate;

	private boolean ajudar = false;

	public void run(){

		setColors(new Color(90, 55, 55), Color.white, Color.blue);
		setAdjustRadarForGunTurn(true);
		setAdjustGunForRobotTurn(true);
		turnRadarRightRadians(2 * Math.PI);

		setMaxVelocity(5);

		while(true){
			lastTimeEnemy++;

			changeSpeed();
			doMoviment();

			doScanner(ajudar);

			doGun(ajudar);
			doFire(ajudar);

			if(ajudar == true && getTime() % 50 == 0){
				ajudar = false;
			}
			execute();
		}
	}

	private void doFire(boolean flag) {
		if(!flag){
			if(getEnergy() > 15){
				setFire(Math.min(400 / getDistanciaEuclidiana(getX(),getY(),advinharXEnemy(),advinharYEnemy()), 3));
			}else{
				setFire(Rules.MIN_BULLET_POWER);
			}
		}else{
			if(getEnergy() > 15){
				setFire(Math.min(400 / getDistanciaEuclidiana(getX(),getY(),helpPosXEnemy,helpPosYEnemy), 3));
			}else{
				setFire(Rules.MIN_BULLET_POWER);
			}
		}
	}

	private void changeSpeed() {
		if(isMax() && getTime() % 70 == 0){
			setMaxVelocity(6);
		}else{
			double v = getVelocity() + Rules.ACCELERATION * 5;
			setMaxVelocity(v);
		}
	}


	private boolean isMax() {
		if(getVelocity() == Rules.MAX_VELOCITY){
			return true;
		}else{
			return false;
		}
	}

	public void onScannedRobot(ScannedRobotEvent event) {
		if(lastEvent == null){
			lastEvent = event;
		}

		if(isTeammate(event.getName())){

			return;

		}else{

			turnRate = getTurnRate(getHeadingRadians(), lastEvent.getHeadingRadians(), getTime(), lastEvent.getTime());

			double giroRobo = (getHeadingRadians() + event.getBearingRadians()) % (2 * Math.PI);

			if(nameEnemy == null || lastTimeEnemy > 5){
				nameEnemy = event.getName();
			}

			if(nameEnemy != null && nameEnemy.equals(event.getName())){
				posXEnemy = getX() + Math.sin(giroRobo) * event.getDistance();
				posYEnemy = getY() + Math.cos(giroRobo) * event.getDistance();
				giroEnemy = event.getBearingRadians();
				headingEnemy = event.getHeadingRadians();
				enemySpeed = event.getVelocity();
				lastTimeEnemy = 0;
			}

			try {
				if(getEnergy() > 80){
					broadcastMessage(new Situacao(posXEnemy, posYEnemy, TipoSituacao.CONFORTAVEL));	
				}else if(getEnergy() > 50){
					broadcastMessage(new Situacao(posXEnemy, posYEnemy, TipoSituacao.RAZOAVEL));
				}else if(getEnergy() > 30){
					broadcastMessage(new Situacao(posXEnemy, posYEnemy, TipoSituacao.SUFOCO));
				}else{
					broadcastMessage(new Situacao(posXEnemy, posYEnemy, TipoSituacao.HORRIVEL));
				}

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			lastEvent = event;

		}

	}

	public void onMessageReceived(MessageEvent event) {
		Situacao s = (Situacao) event.getMessage();
		int valorUtilidade = utilidade(s.getTipoSitucao());

		if(getDistanciaEuclidiana(getX(), getY(), posXEnemy, posYEnemy) * valorUtilidade 
				< getDistanciaEuclidiana(getX(), getY(), s.getEnemyPosX(), s.getEnemyPosY()) * valorUtilidade){
			ajudar = true;
		}
	}

	private int utilidade(int tipo){
		int util = 0;

		if(tipo == TipoSituacao.CONFORTAVEL){
			util = 0;
		}else if(tipo == TipoSituacao.RAZOAVEL){
			if(getEnergy() > 70){
				util = 5;
			}else{
				util = 3;
			}
		}else if(tipo == TipoSituacao.HORRIVEL){
			if(getEnergy() > 70){
				util = 10;
			}else{
				util = 7;
			}
		}else{
			if(getEnergy() > 70){
				util = 10;
			}else{
				util = 2;
			}
		}

		return util;
	}

	public void doMoviment(){

		if (getTime() % 30 == 0)  { 		
			direcao *= -1;		
			setAhead(direcao * 400);
		}
		setTurnRightRadians(giroEnemy + (Math.PI / 2));

	}


	public void onHitWall(HitWallEvent event) {
		setMaxVelocity(Rules.MAX_VELOCITY);
		turnRightRadians(lastEvent.getBearingRadians());
		//direcao *= -1;
		//ahead(lastEvent.getDistance() - 5);
		ahead(100);
	}

	public void onHitByBullet(HitByBulletEvent event) {

	}

	public double advinharXEnemy(){
		return posXEnemy + (enemySpeed * Math.sin(headingEnemy + turnRate));
	}

	public double advinharYEnemy(){
		return posYEnemy + (enemySpeed * Math.cos(headingEnemy + turnRate));
	}

	public double advinharXEnemy(double posX){
		return posX + (enemySpeed * Math.sin(headingEnemy + turnRate));
	}

	public double advinharYEnemy(double posY){
		return posY + (enemySpeed * Math.cos(headingEnemy + turnRate));
	}

	public long getTurnRate(double enemyHeading, double lastEnemyHeading,long timeNow, long timeBefore){
		return (long) ((enemyHeading - lastEnemyHeading) / (timeNow - timeBefore));
	}

	public void doScanner(boolean flag) {
		double deslocamentoRadar;
		//se por um intervalo de tempo não encontrar o inimigo
		//gira o radar
		if(!flag){
			if (lastTimeEnemy > 4) { 	
				deslocamentoRadar = 360;		
			} else {	

				//seta a quantidade necessária para rotação do radar de acordo com a posicao do inimigo
				deslocamentoRadar = getRadarHeadingRadians() - absbearing(getX(),getY(),posXEnemy,posYEnemy);

				if (deslocamentoRadar < 0)
					deslocamentoRadar -= Math.PI/8;
				else
					deslocamentoRadar += Math.PI/8; 
			}
		}else{
			deslocamentoRadar = getRadarHeadingRadians() - absbearing(getX(),getY(),helpPosXEnemy,helpPosYEnemy);

			if (deslocamentoRadar < 0)
				deslocamentoRadar -= Math.PI/8;
			else
				deslocamentoRadar += Math.PI/8; 
		}

		//deslocamentoRadar = 360;
		//gira o radar
		setTurnRadarLeftRadians(NormaliseBearing(deslocamentoRadar));
		//setTurnRadarLeftRadians(deslocamentoRadar);
	}

	public void doGun(boolean flag) {

		//predição do inimigo e rotação da mira para ele
		if(!flag){
			double rotacaoArma = getGunHeadingRadians() - absbearing(getX(),getY(),advinharXEnemy(),advinharYEnemy());
			setTurnGunLeftRadians(NormaliseBearing(rotacaoArma));
		}else{
			double rotacaoArma = getGunHeadingRadians() - absbearing(getX(),getY(),helpPosXEnemy,helpPosYEnemy);
			setTurnGunLeftRadians(NormaliseBearing(rotacaoArma));
		}
	}


	public double absbearing( double x1,double y1, double x2,double y2 )
	{
		double xo = x2-x1;
		double yo = y2-y1;
		double h = getDistanciaEuclidiana( x1,y1, x2,y2 );
		if( xo > 0 && yo > 0 )
		{
			return Math.asin( xo / h );
		}
		if( xo > 0 && yo < 0 )
		{
			return Math.PI - Math.asin( xo / h );
		}
		if( xo < 0 && yo < 0 )
		{
			return Math.PI + Math.asin( -xo / h );
		}
		if( xo < 0 && yo > 0 )
		{
			return 2.0*Math.PI - Math.asin( -xo / h );
		}
		return 0;
	}

	public double getDistanciaEuclidiana( double x1,double y1, double x2,double y2 )
	{
		double xo = x2-x1;
		double yo = y2-y1;
		double h = Math.sqrt( xo*xo + yo*yo );
		return h;	
	}

	//normaliza o giro
	public double NormaliseBearing(double ang) {
		if (ang > Math.PI)
			ang -= 2 * Math.PI;
		if (ang < - Math.PI)
			ang += 2 * Math.PI;
		return ang;
	}

}
